using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using Awesome.Extensions.QualityTools;
using Awesome.Extensions.Reflection;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Awesome.Extensions.Tests
{
    [TestClass]
    public class TestReflection
    {
        [TestMethod]
        public void TestMethodOfDelegate()
        {
            var meth = typeof(TestReflection).GetMethod("TestMethodOfDelegate");

            Method.Of(TestMethodOfDelegate)
                .AssertEquals(meth);

            Method.Of(System.Console.WriteLine);
        }

        private class Foobar
        {
            public const int MAGIC = 0x1223542;

            public void Bar() { }
            public Action Foo(int e)
            {
                return () => { };
            }

            public void SomeAction(int i, char[] j)
            {

            }

            public int SomeFunc(int i, char[] j)
            {
                return MAGIC;
            }

        }

        [TestMethod]
        public void TestMethodOfInstance()
        {
            var foobar = new Foobar();

            var bar = Method.Of<Foobar>(f => f.Bar);
            bar.AssertEquals(Method.Of(foobar.Bar));
        }

       
        [TestMethod]
        public void TestMethodOfResult()
        {
            var meth = Method<string>.Of(System.Console.ReadLine);

            meth.Name.AssertEquals("ReadLine");
            meth.DeclaringType.FullName.AssertEquals("System.Console");
        }

        [TestMethod]
        public void TestMethodOfResultInstance()
        {
            var foobar = new Foobar();

            var meth1 = Method<Action>.Of<Foobar, int>(x => x.Foo);
            var meth2 = Method<Action>.Of<int>(foobar.Foo);

            meth1.AssertEquals(meth2);
        }

        [TestMethod]
        public void TestCurrentMethod()
        {
            var current = Method.Current;
            var @this = Method.Of(TestCurrentMethod);

            current.AssertEquals(@this);
        }

        [MethodImpl(MethodImplOptions.NoInlining)]
        public MethodBase GetCurrentMethod()
        {
            return Method.Calling;
        }

        [TestMethod]
        public void TestCallingMethod()
        {
            GetCurrentMethod().AssertEquals(Method.Current);
        }

        [TestMethod]
        public void TestGetMethod()
        {
            var method = typeof(Foobar).GetMethod<int, char[]>("SomeAction");
            method.AssertEquals(Method.Of<Foobar, int, char[]>(x => x.SomeAction));
        }

        [TestMethod]
        public void TestGetDelegate()
        {
            var act = typeof(Foobar).GetDelegate<Func<int, char[], int>>(new Foobar(), "SomeFunc");

            act(0, null).AssertEquals(Foobar.MAGIC);
        }

    }
}